/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
//#include "ssi_defines.h"

#ifndef __TNode2_H__
#define __TNode2_H__

#pragma warning( disable : 4251 )  // Disable warning messages
// This warning is issued when the template is not exported...
// Exported templates dont seem to work in GCC
// Doesnt seem to cause problem (other than warning here)

/*  To be used in a list, a class/variable must be able to do the
    the following:
     1.  Copy constructor
     2.  Equal Operator
     3.  Comparison Operator

*/

#include <deque>
#include <iterator>
using std::deque;
using std::iterator;

template<class aType>
class /*_declspec(dllexport)*/ TNode2
{
public:
  TNode2();
  ~TNode2();
  void Get(aType& In);
  TNode2 &operator=(TNode2& Other);
  char operator==(const TNode2& Other);
  char isEqual(const TNode2& Other);

  TNode2* Set(aType &inData, TNode2* inPar = 0, TNode2* inNext = 0, TNode2* inPrev = 0, deque<TNode2>* inChildren = 0); 
  TNode2* next();
  TNode2* prev();
  TNode2* par();

  void setNext(TNode2* New);
  void setPrev(TNode2* New);
  void setPar(TNode2* New);
	//void setFChild(TNode2* New);
	void setChildren(deque<TNode2>* New);
  deque<TNode2>* children();

  //TNode2* fchild();

protected:
public:
  TNode2* Next;
  TNode2* Par;
  //TNode2* FChild;
  TNode2* Prev;

	deque<TNode2>* Children;

private:
  aType Data;
};

template<class aType>
TNode2<aType>::TNode2()
{
  Next = 0;
  Par = 0;
	Children = new deque<TNode2>;
  //FChild = 0;
  Prev = 0;
}

template<class aType>
TNode2<aType>::~TNode2()
{
	delete Children;
}

template<class aType>
TNode2<aType>& TNode2<aType>::operator=(TNode2& Other)
{
  Next = 0;
  Par = 0;
  //FChild = 0;
	Children->clear();
  Prev = 0;
  Data = Other.Data;
  return *this;
}

template<class aType>
char TNode2<aType>::isEqual(const TNode2 &Other)
{
  if(Data == Other.Data)
  {
    return 1;
  }
  return 0;
}


template<class aType>
char TNode2<aType>::operator==(const TNode2 &Other)
{
  return isEqual(Other);
}

template<class aType>
void TNode2<aType>::setNext(TNode2* New)
{
  Next = New;
}

template<class aType>
void TNode2<aType>::setPar(TNode2* New)
{
  Par = New;
}

template<class aType>
void TNode2<aType>::setPrev(TNode2* New)
{
  Prev = New;
}

template<class aType>
void TNode2<aType>::setChildren(deque<TNode2>* New)
{
	if(Children){
		delete Children;
	}
	Children = New;
  //FChild = New;
}

template<class aType>
void TNode2<aType>::Get(aType& In)
{
  In = Data;
}

template<class aType>
TNode2<aType>* TNode2<aType>::next()
{
  return Next;
}

template<class aType>
TNode2<aType>* TNode2<aType>::prev()
{
  return Prev;
}

template<class aType>
TNode2<aType>* TNode2<aType>::par()
{
  return Par;
}

//<aType>* TNode2<aType>::fchild()
template<class aType>
deque<TNode2>* TNode2<aType>::children()
{
  return Children;
}

template<class aType>
TNode2<aType>* TNode2<aType>::Set(aType &inData, TNode2* inPar, TNode2* inNext, TNode2* inPrev, deque<TNode2>* inChildren)
{
  if(inNext)    Next = inNext;
  if(inPar)     Par = inPar;
	Children = inChildren;
  //if(inFChild)  FChild = inFChild;
  if(inPrev)    Prev = inPrev;
  Data = inData;
  return this;
}

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

#define SSI_Node2 TNode2<aType>

template<class aType>
class	/*_declspec(dllexport)*/ TNode2Tree
{
public:
	TNode2Tree();
  ~TNode2Tree();
  SSI_Node2* add(aType& inData, SSI_Node2* Par);
  SSI_Node2* push(aType& inData);
  char pop(aType& inData);
  SSI_Node2* find(aType &inData, SSI_Node2* First = 0);	
	int indexof(TNode2<aType> *InNode);

	int clear_range(SSI_Node2* First, SSI_Node2* Last);
	SSI_Node2* insert_after(aType &inData, SSI_Node2* Before);
	SSI_Node2* insert_before(aType &inData, SSI_Node2* After);

  SSI_Node2* getTop();
  //aType operator[](SSI_INT64 Index);
  SSI_Node2* operator[](int Index);
  TNode2Tree &operator=(TNode2Tree& Other);
  void Clear();
protected:
private:
  //void clear(SSI_Node2* In);
  //void copyTree(SSI_Node2* Par, SSI_Node2* toCopy);

	deque<TNode2>* Tops;

  //SSI_Node2* Top;
};

template<class aType>
void TNode2Tree<aType>::Clear()
{
	if(Tops){
		delete Tops;
	}
	Tops = 0;
  //clear(Top);
  //Top = 0;
}

template<class aType>
TNode2Tree<aType> &TNode2Tree<aType>::operator=(TNode2Tree& Other)
{
	*Tops = *(Other.Tops);

  //clear(Top);
	//clear(Tops);
  //Tops = 0;
  //copyTree(0, Other.Tops);
  return *this;
}

/*
template<class aType>
void TNode2Tree<aType>::copyTree(SSI_Node2* Par, SSI_Node2* toCopy)
{
	if(!toCopy){
		return;
	}
  SSI_Node2* copyTemp = toCopy;
  SSI_Node2* Ret = 0;
	aType aTemp;
  while(copyTemp)
  {
    copyTemp->Get(aTemp);
    Ret = add(aTemp, Par);
		copyTree(Ret, copyTemp->FChild);
		copyTemp = copyTemp->Next;
  }
}
*/

template<class aType>
SSI_Node2* TNode2Tree<aType>::operator[](int Index)
{
	if(!Tops) return 0;
	if(Index >= 0 && Index < Tops->size()){
		return &((*Tops).at(Index));
	}

//  int i = 0;
//  SSI_Node2* Pos = Top;
//  while(Pos)
//  {
//    if(i == Index) return Pos;
//    i++;
//		if(Pos->Next){
//			Pos = Pos->Next;
//		}else{
//			if(Index == -1){
//				return Pos;
//			}else{
//				return 0;
//			}
//		}
//    
//  }
//  return 0;
}

template<class aType>
TNode2Tree<aType>::TNode2Tree()
{
	Tops = new deque<TNode2>;
  //Top = 0;
}

template<class aType>
TNode2Tree<aType>::~TNode2Tree()
{
	if(Tops) delete Tops;
	Tops = 0;
  //clear(Top);
}


// Need to redo this one still
template<class aType>
SSI_Node2* TNode2Tree<aType>::add(aType &inData, SSI_Node2* Par)
{
  SSI_Node2* locFirst;
  SSI_Node2* add;

  aType aTemp;

  if(Par == 0)
  {
    return push(inData);
  }
  else
  {
    if(Par->FChild)
    {
			locFirst = Par->FChild;
    }
    else
    {
      add = new SSI_Node2;
      add->Set(inData, Par);
			Par->FChild = add;
      //Par->Get(aTemp);
      //Par->Set(aTemp, Par->par(), Par->next(), Par->prev(), add);
      return add;
    }    
  }

	while(locFirst->Next)
  {
    locFirst = locFirst->Next;
  }
  add = new SSI_Node2;
  add->Set(inData, locFirst->par(), 0, locFirst, 0);
	locFirst->Next = add;
  //locFirst->Get(aTemp);
  //locFirst->Set(aTemp, locFirst->par(), add, locFirst->prev(), locFirst->fchild());   
  return add;
}

// Need to redo this one still
template<class aType>
SSI_Node2* TNode2Tree<aType>::insert_after(aType &inData, SSI_Node2* Before)
{
  SSI_Node2* add;

	if(!Before){
		return 0;
	}

	add = new SSI_Node2;
	add->Set(inData, Before->par(), Before->next(), Before, 0);
	if(Before->next()){
		Before->next()->setPrev(add);
	}
	Before->setNext(add);

	return add;
}

// Need to redo this one still
template<class aType>
SSI_Node2* TNode2Tree<aType>::insert_before(aType &inData, SSI_Node2* After)
{
  SSI_Node2* add;

	if(!After){
		return 0;
	}

	add = new SSI_Node2;
	add->Set(inData, After->par(), After, After->prev(), 0);

	if(After->prev()){
		After->prev()->setNext(add);
	}

	After->setPrev(add);
	if(After == Top){
		Top = add;
	}

	return add;
}

// Need to redo this one still
template<class aType>
SSI_Node2* TNode2Tree<aType>::push(aType &inData)
{
  aType Temp;
  SSI_Node2* locTop;
  SSI_Node2* add;
  if(Top == 0){
    Top = new SSI_Node2;
    Top->Set(inData);
    return Top;
  }else{
    locTop = Top;
  }
  while(locTop->Next){
    locTop = locTop->Next;
  }
  add = new SSI_Node2;
  add->Set(inData, 0, 0, locTop, 0);
	locTop->Next = add;
	//locTop->Get(Temp);
  //locTop->Set(Temp, locTop->par(), add, locTop->prev(), locTop->fchild());
  return add;
}

// Need to redo this one still
template<class aType>
char TNode2Tree<aType>::pop(aType& inData)
{

  aType Temp;

  if(Top == 0) return 0;

  SSI_Node2* locTop = Top;
  SSI_Node2* locPar = 0;
  while(locTop->next())
  {
    locTop = locTop->next();
  }

  locTop->Get(inData);
  locPar = locTop->prev();
  if(locPar)
  {
    locPar->Get(Temp);
    locPar->Set(Temp, locPar->par());
    locPar->setNext(0);
    clear(locTop);
  }
  else
  {
		clear(Top);
    Top = 0;
  }
  
  return 1;
}

/*
template<class aType>
void TNode2Tree<aType>::clear(SSI_Node2* In)
{
	// This recursion causes a stack overflow...
	SSI_Node2* Temp;
	SSI_Node2* TempNext = 0;
	SSI_Node2* TempChild = 0;

  if(In == 0) return;
	Temp = In;
	while(Temp){
		TempNext = Temp->Next;
		TempChild = Temp->FChild;
		delete Temp;
		clear(TempChild);
		Temp = TempNext;
	}	
  //if(Temp = In->fchild())
  //{
	//	TempNext = Temp->fchild();
  //  clear(In->fchild());
  //}
  //if(In->next())
  //{
  //  clear(In->next());
  //}
  //if(In) delete(In);
  //In = 0;
}
*/

/*
template<class aType>
int TNode2Tree<aType>::clear_range(SSI_Node2* First, SSI_Node2* Last)
{
	if(!First) return 0;
	if(!Last) return 0;
	if(First->par() != Last->par()){
		return 0;
	}

	SSI_Node2* Curr = First;
	SSI_Node2* Par = 0;
	SSI_Node2* Prev = First->prev();
	SSI_Node2* Next = Last->next();
	SSI_Node2* Temp;

	while(Curr){
		if(Curr == Last){
			break;
		}else{
			Temp = Curr;
			if(Curr->fchild()){
				clear(Curr->fchild());					
			}
 			Curr = Curr->next();

			// Make sure that if you parents first child, clear it...
			if(Temp->par()){
				if(Temp = Temp->par()->fchild()){
					Temp->par()->setFChild(0);
				}
			}

			// Make sure that if you delete Top, clear it...
			if(Temp == Top){
				Top = 0;
			}


			delete Temp;

		}
	}

	if(Curr != Last){
		return 0;
	}

	if(Last->fchild()){
		clear(Last->fchild());					
	}
	if(Last == Top){
		Top = 0;
	}
	delete Last;
		
	if(Prev){
		Prev->setNext(Next);
	}else{
		if(Next){
			Par = Next->par();
			if(Par){
				clear(Par->fchild());
				Par->setFChild(Next);
			}else{
				if(Top){
					clear(Top);
				}
				Top = Next;
			}
		}
	}
	if(Next){
		Next->setPrev(Prev);
	}
  return 1;
}
*/



// Need to redo this one still
template<class aType>
int TNode2Tree<aType>::indexof(TNode2<aType> *InNode)
{
	int ctr = 0;
  SSI_Node2* loc;

	loc = Top;
	while(loc){
		if(loc == InNode) return ctr;
    loc = loc->next();
		ctr++;
	}
	return -1;
}

// Need to redo this one still
template<class aType>
SSI_Node2* TNode2Tree<aType>::find(aType &inData, SSI_Node2* First)
{
	TNode2 aNode;
	aNode.Set(inData, 0, 0, 0, 0);

	
	//Tops->

//  SSI_Node2* loc;
//  SSI_Node2* Temp;
//  aType aTemp;
//  if(First == 0)
//  {
//    loc = Top;
//  }
//  else
//  {
//    loc = First;
//  }
//  
//  if(!loc) return 0;
//
//  Temp = loc;
//  while(Temp)
//  {
//    Temp->Get(aTemp);
//    if(aTemp == inData) return Temp;
//    Temp = Temp->next();
//  }

//  Temp = loc;
//  while(Temp)
//  {
//    if(Temp->fchild())
//    {
//      loc = find(inData, Temp->fchild());
//      if(loc) return loc;
//    }
//    Temp = Temp->next();
//  }
//  return 0;
}

template<class aType>
SSI_Node2* TNode2Tree<aType>::getTop()
{
	if(!Tops) return 0;
	if(Tops->size() > 0){
		return &(Tops->at(0));
	}
	return 0;

  //return Top;
}


//#pragma warning( default : 4251 )  // Disable warning messages


#endif



